package main

import (
	"errors"
	"fmt"
	"math/rand"
)

// 数组模拟队列
// 队列是一个有序列表，可以用数组或链表实现
// 遵循先入先出的原则 FIFO
func main() {
	simulateCircularQueue()
}

// simulateUnidirectionalQueue
//
//	@Description: 模拟环形队列： 先赋/取值 再移动指针，同时需要空一个位置做约定，所以容量 = MaxSize -1
//
// ------------队列信息start------------
// Head=0 Tail=3
// |  0  ||  1  ||  2  ||  3  |
// |  3  ||  1  ||  7  ||  0  |
// ------------队列信息end------------
func simulateCircularQueue() {
	q := &Queue{
		MaxSize: 4,
		Head:    0,
		Tail:    0,
		Array:   [4]int{},
	}
	var key int
	for {
		fmt.Println("1. 添加数据到队列	2. 获取数据	3. 显示队列")
		fmt.Scanln(&key)
		switch key {
		case 1:
			var v = rand.Intn(8) + 1
			err := q.addQueue(v)
			if err != nil {
				fmt.Printf("添加元素:%v ERROR=%v \n", v, err)
			} else {
				fmt.Printf("添加元素成功:%v\n", v)
			}
			q.showQueue()
		case 2:
			value, err := q.getQueue()
			if err != nil {
				fmt.Printf("获取元素失败 ERROR=%v \n", err)
			} else {
				fmt.Printf("获取元素成功:%v\n", value)
			}
			q.showQueue()
		case 3:
			q.showQueue()
		default:
			fmt.Println("输入错误，请重新输入！")
		}
	}

}

type Queue struct {
	MaxSize int    // 队列最大容量
	Array   [4]int // 存放数据
	Head    int    // 指向队列头
	Tail    int    // 指向队列尾
	Count   int    // 队列中元素个数  (Tail+MaxSize - head ) % MaxSize
}

// addQueue
//
//	@Description:
//	@receiver q
//	@param value
//	@return err
func (q *Queue) addQueue(value int) (err error) {
	if (q.Tail+1)%q.MaxSize == q.Head {
		return errors.New("队列已满")
	}
	q.Array[q.Tail] = value           //把值给尾部
	q.Tail = (q.Tail + 1) % q.MaxSize //tail向后移动一位
	return nil

}

// getQueue
//
//	@Description: 获取
//	@receiver q
//	@return value
//	@return err
func (q *Queue) getQueue() (value int, err error) {
	if q.Head == q.Tail {
		return 0, errors.New("队列为空")
	}
	value = q.Array[q.Head]           //获取队头元素
	q.Array[q.Head] = 0               //已经取过的位置赋值0
	q.Head = (q.Head + 1) % q.MaxSize // 头指针向后移动一位
	return value, nil
}

// Size
//
//	@Description: 元素个数
//	@receiver q
//	@return int
func (q *Queue) Size() int {
	return (q.Tail + q.MaxSize - q.Head) % q.MaxSize
}

// showQueue
//
//	@Description: 打印队列信息
//	@receiver q
func (q *Queue) showQueue() {
	//fmt.Println("------------队列信息start------------")
	fmt.Printf("Head=%d Tail=%d \n", q.Head, q.Tail)
	for i := 0; i < len(q.Array); i++ {
		fmt.Printf("|  %d  |", i)
	}
	fmt.Println()
	for i := 0; i < len(q.Array); i++ {
		fmt.Printf("|  %d  |", q.Array[i])
	}
	fmt.Println()
	//fmt.Println("------------队列信息end------------")
}
